/*
 * SearchWidget.cpp
 *
 *  Created on: Jan 13, 2011
 *      Author: kmueller
 */

#include "SearchWidget.h"

#include "RouteWidget.h"

#include "../logic/Main.h"
#include "../logic/SearchService.h"
#include "../logic/Helpers.h"

#include <QGeoCoordinate>
#include <QtGui>
#include <QtGlobal>

/****************************************************************************/

SearchLineEdit::SearchLineEdit(const QString& contents, QWidget* parent) :
	QLineEdit(contents, parent) {
	content = contents;
	connect(this, SIGNAL(selectionChanged()), this, SLOT(changeContent()));
}

void SearchLineEdit::changeContent() {
	if (text() == "") {
		setText(content);
	} else if (text() == content) {
		setText("");
	}
}

FullOperationDialog::FullOperationDialog(LabeledCoordinate& coord,
		QWidget* parent) :
	QDialog(parent) {
	coordinate = &coord;

	setWindowTitle(coordinate->getLabel());

	QPushButton* showOnMap = new QPushButton(tr("Show on Map"), this);
	connect(showOnMap, SIGNAL(clicked()), this, SLOT(showOnMap()));

	QPushButton* asOrigin = new QPushButton(tr("Use as origin"), this);
	connect(asOrigin, SIGNAL(clicked()), this, SLOT(useAsOrigin()));

	QPushButton* asDestination =
			new QPushButton(tr("Use as destination"), this);
	connect(asDestination, SIGNAL(clicked()), this, SLOT(useAsDestination()));

	QPushButton* back = new QPushButton(tr("back"), this);
	connect(back, SIGNAL(clicked()), this, SLOT(close()));

	QBoxLayout* main = new QVBoxLayout(this);
	main->addWidget(showOnMap);
	main->addWidget(asOrigin);
	main->addWidget(asDestination);
	main->addWidget(back);

	this->setLayout(main);

	this->resize(this->sizeHint());
}

void FullOperationDialog::showOnMap() {
	Main::getInstance().getSettings().getRecentPlaces()->add(*coordinate);
	emit onMap(*coordinate);
	close();
}

void FullOperationDialog::useAsOrigin() {
	Main::getInstance().getSettings().getRecentPlaces()->add(*coordinate);
	emit asOrigin(*coordinate);
	close();
}

void FullOperationDialog::useAsDestination() {
	Main::getInstance().getSettings().getRecentPlaces()->add(*coordinate);
	emit asDestination(*coordinate);
	close();
}

SmallOperationDialog::SmallOperationDialog(LabeledCoordinate& coord,
		QWidget* parent) :
	QDialog(parent) {
	coordinate = &coord;

	setWindowTitle(coordinate->getLabel());

	QPushButton* use = new QPushButton(tr("Accept"), this);
	connect(use, SIGNAL(clicked()), this, SLOT(use()));

	QPushButton* back = new QPushButton(tr("back"), this);
	connect(back, SIGNAL(clicked()), this, SLOT(close()));

	QBoxLayout* main = new QVBoxLayout(this);
	main->addWidget(use);
	main->addWidget(back);

	this->setLayout(main);

	this->resize(this->sizeHint());
}

void SmallOperationDialog::use() {
	Main::getInstance().getSettings().getRecentPlaces()->add(*coordinate);
	emit use(*coordinate);
	close();
}

/****************************************************************************/

SearchWidget::SearchWidget(QWidget *parent) :
	QDialog(parent) {
	init(NONE);
}

SearchWidget::SearchWidget(Type type, RouteWidget *parent) :
	QDialog(parent) {
	init(type);
}

/*SearchWidget::~SearchWidget() {
 //	delete searchCity;
 //	delete searchStreet;
 //	delete selection;
 //	delete bSearch;
 //	delete bBack;
 //	delete information;
 delete parent();
 }*/

void SearchWidget::init(Type t) {
	type = t;

	setWindowTitle(tr("Search place"));
	createComponents();

	showSearchCity();

connect(&Main::getInstance().getSearchService(), SIGNAL(resultAvailable(QAbstractListModel*)), this, SLOT(updateSelectionBox(QAbstractListModel*)));
}

void SearchWidget::changeSelectionModel(QAbstractListModel* model) {
	QItemSelectionModel *m = selection->selectionModel();
	selection->setModel(model);
	delete m;
}

void SearchWidget::createComponents() {
	searchCity = new SearchLineEdit(tr("City"));
	searchStreet = new SearchLineEdit(tr("Street"));
	selection = new QListView();
	bSearch = new QPushButton(tr("Search"));
	bBack = new QPushButton(tr("Back"));
	information = new QLabel();

	connect(bSearch, SIGNAL(clicked()), this, SLOT(search()));
	connect(bBack, SIGNAL(clicked()), this, SLOT(backToCity()));
}

void SearchWidget::hideAll() {
	searchCity->hide();
	searchStreet->hide();
	selection->hide();
	bSearch->hide();
	bBack->hide();
	information->hide();
}

void SearchWidget::createSearchCity() {
	hideAll();
	QBoxLayout* searchCityLayout = new QHBoxLayout();
	QVBoxLayout* leftLayout = new QVBoxLayout();

	leftLayout->addWidget(searchCity);
	leftLayout->addWidget(selection);

	QVBoxLayout* rightLayout = new QVBoxLayout();

	rightLayout->addWidget(bSearch);
	rightLayout->addStretch();

	searchCityLayout->addLayout(leftLayout, 8);
	searchCityLayout->addLayout(rightLayout, 1);

	searchCity->show();
	selection->show();
	bSearch->show();

	delete layout();
	this->setLayout(searchCityLayout);
}

void SearchWidget::showSearchCity() {
	setState(SEARCH_CITY);

	QAbstractListModel* model =
			Main::getInstance().getSettings().getRecentPlaces()->model(
					selection);
	changeSelectionModel(model);

	this->createSearchCity();
}

void SearchWidget::createSearchStreet() {
	hideAll();
	QBoxLayout* searchStreetLayout = new QHBoxLayout();

	QVBoxLayout* leftLayout = new QVBoxLayout();

	leftLayout->addWidget(information);
	leftLayout->addWidget(searchStreet);
	leftLayout->addWidget(selection);

	QVBoxLayout* rightLayout = new QVBoxLayout();

	rightLayout->addWidget(bSearch);
	rightLayout->addStretch();
	rightLayout->addWidget(bBack);

	searchStreetLayout->addLayout(leftLayout, 8);
	searchStreetLayout->addLayout(rightLayout, 1);

	information->show();
	searchStreet->show();
	selection->show();
	bSearch->show();
	bBack->show();

	delete layout();
	this->setLayout(searchStreetLayout);
}

void SearchWidget::showSearchStreet() {
	// TODO: das muss wieder einkommentiert werden
	//	information->setText(tr("City: %1").arg(selectedCity.getLabel()));

	this->createSearchStreet();
}

void SearchWidget::reassignConnections() {
	switch (getState()) {
	case SEARCH_CITY:
		selection->disconnect(this);
		connect(selection, SIGNAL(clicked(const QModelIndex &)), this, SLOT(showOperations(const QModelIndex&)));
		break;

	case SELECT_CITY:
		selection->disconnect(this);
		connect(selection, SIGNAL(clicked(const QModelIndex &)), this, SLOT(selectCity(const QModelIndex&)));
		break;

	case SEARCH_STREET:
		selection->disconnect(this);
		connect(selection, SIGNAL(clicked(const QModelIndex &)), this, SLOT(showOperations(const QModelIndex&)));
		break;

	case SELECT_STREET:
		selection->disconnect(this);
		connect(selection, SIGNAL(clicked(const QModelIndex &)), this, SLOT(showOperations(const QModelIndex&)));
		break;
	}
}

void SearchWidget::search() {
	State state = getState();
	switch (state) {
	case SEARCH_CITY:
		setState(SELECT_CITY);
	case SELECT_CITY: {
		// TODO: search for country id
		int countryId = 0;
		QString s = searchCity->text();
		Main::getInstance().getSearchService().searchCity(s, countryId);
	}
		break;

	case SEARCH_STREET:
		setState(SELECT_STREET);
	case SELECT_STREET: {
		// search for streets in the city which is stored in selectedCity
		QString s = searchStreet->text();
		Main::getInstance().getSearchService().searchStreet(s, selectedCity);
	}
		break;
	default:
		qWarning() << "Unsupported search handler";
	}
}

void SearchWidget::updateSelectionBox(QAbstractListModel* model) {
	changeSelectionModel(model);
}

void SearchWidget::backToCity() {
	this->showSearchCity();
}

void SearchWidget::showOperations(const QModelIndex& index) {
	const ISearchModel* model = dynamic_cast<const ISearchModel*>(index.model());

	// this has to be stored in a class attribute because we'll
	// have to read the variable in the route widget
	selectedCoordinate = model->get(index.row());

	if (type == NONE) {
		FullOperationDialog op(selectedCoordinate, this);
		connect(&op, SIGNAL(onMap(const LabeledCoordinate&)), this, SLOT(showOnMap(const LabeledCoordinate&)));
		connect(&op, SIGNAL(asOrigin(const LabeledCoordinate&)), this, SLOT(useAsOrigin(const LabeledCoordinate&)));
		connect(&op, SIGNAL(asDestination(const LabeledCoordinate&)), this, SLOT(useAsDestination(const LabeledCoordinate&)));
		op.exec();
	} else {
		SmallOperationDialog op(selectedCoordinate, this);
		connect(&op, SIGNAL(use(const LabeledCoordinate&)), this, SLOT(useAs(const LabeledCoordinate&)));
		op.exec();
	}
}

void SearchWidget::showOnMap(const LabeledCoordinate& coord) {
	emit centeringMap(coord);
	close();
}

void SearchWidget::useAs(const LabeledCoordinate& coord) {
	switch (type) {
	case ORIGIN:
		static_cast<RouteWidget*> (parent())->setOrigin(coord);
		break;
	case DESTINATION:
		static_cast<RouteWidget*> (parent())->setDestination(coord);
		break;
	default:
		qCritical() << "Impossible case reached";
	}
	close();
}

void SearchWidget::useAsOrigin(const LabeledCoordinate& coord) {
	RouteWidget route((QWidget*) parent());
	route.setOrigin(coord);
	route.exec();
	close();
}

void SearchWidget::useAsDestination(const LabeledCoordinate& coord) {
	RouteWidget route((QWidget*) parent());
	route.setDestination(coord);
	route.exec();
	close();
}

void SearchWidget::selectCity(const QModelIndex& index) {
	if (getState() == SELECT_CITY) {
		const SearchService::CityResult* model =
				dynamic_cast<const SearchService::CityResult*> (index.model());
		LabeledCoordinate coord = model->get(index.row());
		selectedCity = model->getCityId(index.row());

		// FIXME: don't use RecentPlaces for this
		RecentPlaces* tmp = new RecentPlaces();
		QString name = tr("Somewhere in %1").arg(coord.getLabel());
		QtMobility::QGeoCoordinate c =
				static_cast<QtMobility::QGeoCoordinate> (coord);
		tmp->add(name, c);
		QAbstractListModel * newmodel = tmp->model();
		changeSelectionModel(newmodel);

		setState(SEARCH_STREET);
		showSearchStreet();
	} else {
		// I guess this is not necessary because the OperationsDialogs will handle this case
		qWarning() << "Unsupported case reached!!!";
	}
}

void SearchWidget::setState(State s) {
	state = s;
	reassignConnections();
}

SearchWidget::State SearchWidget::getState() {
	return state;
}
